﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using ttbit.form.impl;
using ttbit.IGL;
using ttbit.math;

namespace ttbit.core
{
    public class UniformValue
    {
        public UniformValue(ShaderPool.UniformType type, int uniform_pos)
        {
            unitype = type;
            uniid = uniform_pos;
            if (type == ShaderPool.UniformType.SAMPLER1D || type == ShaderPool.UniformType.SAMPLER2D || type == ShaderPool.UniformType.SAMPLER3D)
            {

            }
            if (IsInt)
                intvalue = new int[elementsize];
            else
                value = new float[elementsize];
        }
        public ShaderPool.UniformType unitype
        {
            get;
            private set;
        }
        public int uniid
        {
            get;
            private set;
        }
        public int elementsize
        {
            get
            {
                switch (unitype)
                {
                    case ShaderPool.UniformType.BOOL:
                    case ShaderPool.UniformType.INT:
                    case ShaderPool.UniformType.FLOAT:
                        return 1;
                    case ShaderPool.UniformType.VEC2:
                    case ShaderPool.UniformType.IVEC2:
                        return 2;
                    case ShaderPool.UniformType.VEC3:
                    case ShaderPool.UniformType.IVEC3:
                        return 3;
                    case ShaderPool.UniformType.VEC4:
                    case ShaderPool.UniformType.IVEC4:
                        return 4;
                    case ShaderPool.UniformType.MAT2:
                        return 4;
                    case ShaderPool.UniformType.MAT3:
                        return 9;
                    case ShaderPool.UniformType.MAT2X3:
                        return 6;
                    case ShaderPool.UniformType.MAT4:
                        return 16;
                    default:
                        return 0;
                }
            }
        }
        public bool IsInt
        {
            get
            {
                switch (unitype)
                {
                    case ShaderPool.UniformType.BOOL:
                    case ShaderPool.UniformType.INT:
                    case ShaderPool.UniformType.IVEC2:
                    case ShaderPool.UniformType.IVEC3:
                    case ShaderPool.UniformType.IVEC4:

                        return true;

                    default:
                        return false;
                }
            }
        }
        public float[] value;
        public int[] intvalue;
        public int texid;
    }

    //主要为batcher 服务，mesh 和 材质不能彻底分开了
    //材质就是 prog uniforms 和一些渲染开关
    //RenderState
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct RenderVertex
    {
        public float X;
        public float Y;
        public float Z;
        public float U;
        public float V;
        public byte R;
        public byte G;
        public byte B;
        public byte A;
        public float U2;
        public float V2;
        public byte UPal;
        public byte VPal;
        public static int Size => 34;

    }
    public class RenderPass : IDisposable
    {
        public ColorF color;

        int vbo = -1;
        int ebo = -1;
        int vao = -1;
        int vertexcount;
        int indexcount;
        public Material material
        {
            get;
            private set;
        }
        public bool UseEbo
        {
            get;
            private set;
        }
        public RenderPass()
        {
        }
        public void SetMaterial(Material mat, bool _useEbo)
        {
            if (vbo < 0)
                vbo = Graphics.GL.GenBuffer();
            if (ebo < 0)
                ebo = Graphics.GL.GenBuffer();
            if (vao < 0)
                vao = Graphics.GL.GenVertexArray();
            this.UseEbo = _useEbo;
            if (this.material != mat)
            {
                material = mat;

                Graphics.GL.BindVertexArray(vao);
                //固定格式 pos uv color
                {//这三件事可以vao一起办了
                    Graphics.GL.BindBuffer(IGL.BufferTarget.ArrayBuffer, vbo);//vbo

                    Graphics.GL.EnableVertexAttribArray(mat.prog.attrid_pos);//顶点信息
                    Graphics.GL.VertexAttribPointer(mat.prog.attrid_pos, 3, IGL.VertexAttribPointerType.Float, false, 34, 0);

                    if (mat.prog.attrid_uv >= 0)
                    {
                        Graphics.GL.EnableVertexAttribArray(mat.prog.attrid_uv);
                        Graphics.GL.VertexAttribPointer(mat.prog.attrid_uv, 2, IGL.VertexAttribPointerType.Float, false, 34, 12);
                    }

                    if (mat.prog.attrid_color >= 0)
                    {
                        Graphics.GL.EnableVertexAttribArray(mat.prog.attrid_color);
                        Graphics.GL.VertexAttribPointer(mat.prog.attrid_color, 4, IGL.VertexAttribPointerType.UnsignedByte, true, 34, 20);
                    }

                    if (mat.prog.attrid_uv2 >= 0)
                    {
                        Graphics.GL.EnableVertexAttribArray(mat.prog.attrid_uv2);
                        Graphics.GL.VertexAttribPointer(mat.prog.attrid_uv2, 2, IGL.VertexAttribPointerType.Float, false, 34, 24);
                    }
                    if (mat.prog.attrid_uvpal >= 0)
                    {
                        Graphics.GL.EnableVertexAttribArray(mat.prog.attrid_uvpal);
                        Graphics.GL.VertexAttribPointer(mat.prog.attrid_uvpal, 2, IGL.VertexAttribPointerType.UnsignedByte, true, 34, 32);
                    }

                    if (_useEbo)
                        Graphics.GL.BindBuffer(IGL.BufferTarget.ElementArrayBuffer, ebo);//ebo
                }
                Graphics.GL.BindVertexArray(0);
            }
        }
        //public void SetProg(ShaderPool.ShaderProgram prog, bool useEbo, bool useBlend)
        //{
        //    if (vbo < 0)
        //        vbo = Env.GL.GenBuffer();
        //    if (ebo < 0)
        //        ebo = Env.GL.GenBuffer();
        //    if (vao < 0)
        //        vao = Env.GL.GenVertexArray();
        //    if (material != null)
        //    {
        //        material.ChangeShader(prog);
        //        //renderState.Dispose();
        //    }
        //    else
        //    {
        //        material = new Material(prog);
        //        material.useBlend = useBlend;
        //    }
        //    usbEbo = useEbo;
        //    //if (vao >= 0)
        //    //{
        //    //    GL.DeleteVertexArray(vao);
        //    //}
        //    //vao = GL.GenVertexArray();
        //    Env.GL.BindVertexArray(vao);
        //    //固定格式 pos uv color
        //    {//这三件事可以vao一起办了
        //        Env.GL.BindBuffer(IGL.BufferTarget.ArrayBuffer, vbo);//vbo

        //        Env.GL.EnableVertexAttribArray(prog.attrid_pos);//顶点信息
        //        Env.GL.VertexAttribPointer(prog.attrid_pos, 3, IGL.VertexAttribPointerType.Float, false, 24, 0);

        //        if (prog.attrid_uv >= 0)
        //        {
        //            Env.GL.EnableVertexAttribArray(prog.attrid_uv);
        //            Env.GL.VertexAttribPointer(prog.attrid_uv, 2, IGL.VertexAttribPointerType.Float, false, 24, 12);
        //        }
        //        if (prog.attrid_color >= 0)
        //        {
        //            Env.GL.EnableVertexAttribArray(prog.attrid_color);
        //            Env.GL.VertexAttribPointer(prog.attrid_color, 4, IGL.VertexAttribPointerType.UnsignedByte, true, 24, 20);
        //        }


        //        if (useEbo)
        //            Env.GL.BindBuffer(IGL.BufferTarget.ElementArrayBuffer, ebo);//ebo
        //    }
        //    Env.GL.BindVertexArray(0);

        //}
        public void UpdateVBO(RenderVertex[] buffers, int vertexcount, bool dynamic = false)
        {
            if (vbo < 0)
                vbo = Graphics.GL.GenBuffer();
            Graphics.GL.BindBuffer(IGL.BufferTarget.ArrayBuffer, vbo);
            Graphics.GL.BufferData(IGL.BufferTarget.ArrayBuffer, RenderVertex.Size * vertexcount, buffers,
                dynamic ? IGL.BufferUsage.DynamicDraw : IGL.BufferUsage.StaticDraw);
            this.vertexcount = vertexcount;
        }
        public void UpdateEBO(int[] tris, int indexcount, bool dynamic = false)
        {
            if (ebo < 0)
                ebo = Graphics.GL.GenBuffer();
            Graphics.GL.BindBuffer(BufferTarget.ElementArrayBuffer, ebo);
            Graphics.GL.BufferData(BufferTarget.ElementArrayBuffer, sizeof(int) * indexcount, tris,
                 dynamic ? IGL.BufferUsage.DynamicDraw : IGL.BufferUsage.StaticDraw);
            this.indexcount = indexcount;
        }

        public void Draw(int ebocount = -1)
        {
            Graphics.GL.BindVertexArray(vao);
            material.Apply();




            if (UseEbo)
            {
                if (ebocount < 0)
                    ebocount = indexcount;
                Graphics.GL.DrawElements(IGL.BeginMode.Triangles, ebocount, DrawElementsType.UnsignedInt, IntPtr.Zero); //vbo & vao
            }
            else
            {
                Graphics.GL.DrawArrays(IGL.BeginMode.Triangles, 0, vertexcount);//only vbo
            }
        }

        public void Dispose()
        {
            material.Dispose();
            material = null;
        }
    }
}
